package org.apache.ibatis.executor;

import java.beans.PropertyDescriptor;

import org.apache.ibatis.configuration.BoundSql;
import org.apache.ibatis.configuration.CommandType;
import org.apache.ibatis.configuration.Configuration;
import org.apache.ibatis.configuration.MappedStatement;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.*;

/**
 * @Classname SimpleExecutor
 * @Description TODO
 * @Date 2025/1/16 14:03
 * @Author zhuzhenguo
 */
public class SimpleExecutor implements Executor {

    Map<Integer, Integer> map = new TreeMap<>();

    int findPosition = 0;

    List<String> parameterMappings = new ArrayList<>();

    /**
     * 最终执行JDBC的核心方法
     *
     * @param configuration   配置
     * @param mappedStatement mapped 语句
     * @param parameters       参数
     * @return {@link List}<{@link E}>
     */
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws Exception {
        //1. 获取数据库连接
        Connection connection = configuration.getDataSource().getConnection();
        //2. 获取要执行的sql语句
        // select * from user where id = #{id}
        // select * from user where id = #{id} 解析为 select * from user where id = ?
        // 转换SQL语句，把#{} 转换为 ?
        // 配置文件中的原始的 sql语句
        String sql = mappedStatement.getSql();
        // sql语句转换
        BoundSql boundSql = this.getBoundSql(sql);
        // 获取
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        // 设置sql语句的参数,zzg.study.pojo.User
        String parameterType = mappedStatement.getParameterType();
        Class<?> parameterTypeClass = this.getClassType(parameterType);
        // 获取SQL语句的参数集合
        List<String> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            // 获取SQL语句的参数集合
            String content = parameterMappingList.get(i);
            // mybatis中有对基本数据类型的处理
            if (!"java.lang.Integer".equals(parameterType)) {
                // 暴力反射
                Field declaredField = parameterTypeClass.getDeclaredField(content);
                declaredField.setAccessible(true);
                // 取出参数（只有一个参数）
                Object data = declaredField.get(parameters[0]);
                preparedStatement.setObject(i + 1, data);
            } else {
                preparedStatement.setObject(i + 1, parameters[0]);
            }
        }
        // 执行sql语句
        ResultSet resultSet = null;
        if ("insert".equals(mappedStatement.getSqlType())
                || "update".equals(mappedStatement.getSqlType()) || "delete".equals(mappedStatement.getSqlType())) {
            int res = preparedStatement.executeUpdate();
            List<Integer> resultList = new ArrayList<>();
            resultList.add(res);
            return (List<E>) resultList;
        } else {
            // 查询
            resultSet = preparedStatement.executeQuery();
        }
        // 获取返回值类型
        String resultType = mappedStatement.getResultType();
        Class<?> returnTypeClass = this.getClassType(resultType);
        List<Object> objects = new ArrayList<>();
        // 封装数据
        while (resultSet.next()) {
            // 调无参的构造方法生成对象
            Object o = returnTypeClass.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                // 字段名
                String columnName = metaData.getColumnName(i);
                // 取值
                Object value = resultSet.getObject(columnName);
                // 属性封装
                // 使用内省根据数据库表和实体类的属性的字段对应关系进行封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, returnTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);

                // 使用反射
//                Field declaredField = returnTypeClass.getDeclaredField(columnName);
//                declaredField.setAccessible(true);
//                declaredField.set(o, value);
            }
            objects.add(o);
        }

        return (List<E>) objects;
    }

    /**
     * 根据类的全名称获取Class
     *
     * @param parameterType 参数类型
     * @return {@link Class}<{@link ?}>
     * @throws ClassNotFoundException Class Not Found 异常
     */
    public Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (parameterType != null) {
            return Class.forName(parameterType);
        }
        return null;
    }

    /**
     * 完成sql中#{} 转为 ?
     * 1、将#{}使用？替代
     * 2、解析出#{}里的值进行存储
     *
     * @param sql SQL
     * @return {@link BoundSql}
     */
    private BoundSql getBoundSql(String sql) {
        // 完成sql语句解析工作
        parserSql(sql);
        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
        for (Map.Entry<Integer, Integer> entry : entries) {
            Integer key = entry.getKey() + 2;
            Integer value = entry.getValue();
            parameterMappings.add(sql.substring(key, value));
        }
        for (String s : parameterMappings) {
            sql = sql.replace("#{" + s + "}", "?");
        }
        return new BoundSql(sql, parameterMappings);
    }

    private void parserSql(String sql) {
        int openIndex = sql.indexOf("#{", findPosition);
        if (openIndex != -1) {
            int endIndex = sql.indexOf("}", findPosition + 1);
            if (endIndex != -1) {
                map.put(openIndex, endIndex);
                findPosition = endIndex + 1;
                parserSql(sql);
            } else {
                System.out.println("SQL语句中参数错误");
            }
        }

    }


}
